package com.fmdj.customer.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.codingapi.txlcn.tc.annotation.LcnTransaction;
import com.fmdj.common.exception.GlobalException;
import com.fmdj.common.util.CommonResult;
import com.fmdj.common.util.PageUtils;
import com.fmdj.common.wxpay.MyWXPayConfig;
import com.fmdj.common.wxpay.WXPay;
import com.fmdj.common.wxpay.WXPayConstants;
import com.fmdj.common.wxpay.WXPayUtil;
import com.fmdj.customer.controller.form.*;
import com.fmdj.customer.feign.*;
import com.fmdj.customer.service.CustomerService;
import com.fmdj.customer.service.OrderService;
import com.fmdj.customer.utils.ReturnMessage;
import com.fmdj.mps.controller.form.CalculateTripDistanceAndDurationForm;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.fmdj.mps.controller.form.SearchBefittingDriverAboutOrderForm;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Service
@Slf4j
public class OrderServiceImpl implements OrderService {

    @Autowired
    private OdrServiceApi odrServiceApi;

    @Autowired
    private MapServiceApi mapServiceApi;

    @Autowired
    private FeeCalculatorServiceApi feeCalculatorServiceApi;

    @Autowired
    private SnmServiceApi snmServiceApi;

    @Autowired
    private DrServiceApi drServiceApi;

    @Autowired
    private VhrServiceApi  vhrServiceApi;

    @Autowired
    private CstServiceApi cstServiceApi;

    @Autowired
    private WXPayUtil wxPayUtil;

    @Autowired
    private MyWXPayConfig myWxPayConfig;
    @Override
    public HashMap createOrder(CreateOrderForm form) {

        //构造返回结果集
        HashMap<Object, Object> result = new HashMap<>();

        //取出前端提交的数据
        Long customerId = form.getCustomerId();
        String startPlace = form.getStartPlace();
        String startPlaceLatitude = form.getStartPlaceLatitude();
        String startPlaceLongitude = form.getStartPlaceLongitude();
        String endPlace = form.getEndPlace();
        String endPlaceLatitude = form.getEndPlaceLatitude();
        String endPlaceLongitude = form.getEndPlaceLongitude();
        String favourFee = form.getFavourFee();
        String carPlate = form.getCarPlate();
        String carType = form.getCarType();

        //重新估算里程以及时间 虽然系统默认已经计算了，但是如果用户长时间停留在界面，而用户的位置改变，那么系统默认的里程时间可能不准确，所以需要重新计算
        CalculateTripDistanceAndDurationForm form1 = new CalculateTripDistanceAndDurationForm();
        form1.setMode("driving");
        form1.setStartPlaceLatitude(startPlaceLatitude);
        form1.setStartPlaceLongitude(startPlaceLongitude);
        form1.setEndPlaceLatitude(endPlaceLatitude);
        form1.setEndPlaceLongitude(endPlaceLongitude);
        CommonResult commonResult1 = mapServiceApi.calculateTripDistanceAndDuration(form1);
        HashMap hashMap = (HashMap) commonResult1.get(CommonResult.RETURN_RESULT);
        String mileage = MapUtil.getStr(hashMap, "mileage");
        Integer minute = MapUtil.getInt(hashMap, "minute");

        /*
         * 估算订单费用
         * new DateTime().toTimeStr() : "HH:mm:ss"
         * */
        RideChargeCalculatorForm form2 = new RideChargeCalculatorForm();
        form2.setMileage(mileage);
        form2.setTime(new DateTime().toTimeStr());
        CommonResult commonResult2 = feeCalculatorServiceApi.rideChargeCalculator(form2);
        //上面的map没用了 这里可以复用
        hashMap = (HashMap) commonResult2.get(CommonResult.RETURN_RESULT);
        String expectsFee = MapUtil.getStr(hashMap, "amount"); //amount就是预估费用
        Long chargeRuleId = MapUtil.getLong(hashMap, "chargeRuleId");
        Short baseMileage = MapUtil.getShort(hashMap, "baseMileage");
        String baseMileagePrice = MapUtil.getStr(hashMap, "baseMileagePrice");
        String exceedMileagePrice = MapUtil.getStr(hashMap, "exceedMileagePrice");
        String mileageFee = MapUtil.getStr(hashMap, "mileageFee");
        Short baseMinute = MapUtil.getShort(hashMap, "baseMinute");
        String exceedMinutePrice = MapUtil.getStr(hashMap, "exceedMinutePrice");
        Short waitingFee = MapUtil.getShort(hashMap, "waitingFee");
        Short baseReturnMileage = MapUtil.getShort(hashMap, "baseReturnMileage");
        String exceedReturnPrice = MapUtil.getStr(hashMap, "exceedReturnPrice");
        String returnMileage = MapUtil.getStr(hashMap, "returnMileage");

        //查询附近符合订单条件的司机
        SearchBefittingDriverAboutOrderForm form4 = new SearchBefittingDriverAboutOrderForm();
        form4.setStartPlaceLatitude(startPlaceLatitude);
        form4.setStartPlaceLongitude(startPlaceLongitude);
        form4.setEndPlaceLatitude(endPlaceLatitude);
        form4.setEndPlaceLongitude(endPlaceLongitude);
        form4.setMileage(mileage);
        CommonResult commonResult4 = mapServiceApi.selectBefittingDriverAboutOrder(form4);
        ArrayList<HashMap> list = (ArrayList<HashMap>) commonResult4.get(CommonResult.RETURN_RESULT); //hashmap封装这司机的id和距离
        if (list.size()>0) {
            //将获取的参数保存到insertOrderForm中
            InsertOrderForm form3 = new InsertOrderForm();
            //UUID字符串，充当订单号，微信支付时候会用上
            form3.setUuid(IdUtil.simpleUUID());
            form3.setCustomerId(customerId);
            form3.setStartPlace(startPlace);
            form3.setStartPlaceLatitude(startPlaceLatitude);
            form3.setStartPlaceLongitude(startPlaceLongitude);
            form3.setEndPlace(endPlace);
            form3.setEndPlaceLatitude(endPlaceLatitude);
            form3.setEndPlaceLongitude(endPlaceLongitude);
            form3.setExpectsMileage(mileage); // expectsMileage是从重新预估路程中得到
            form3.setExpectsFee(expectsFee);
            form3.setFavourFee(favourFee);
            form3.setChargeRuleId(chargeRuleId);
            form3.setCarPlate(carPlate);
            form3.setCarType(carType);
            form3.setDate(new DateTime().toDateStr()); //这里默认使用当前系统时间时间
            form3.setBaseMileage(baseMileage);
            form3.setBaseMileagePrice(baseMileagePrice);
            form3.setExceedMileagePrice(exceedMileagePrice);
            form3.setBaseMinute(baseMinute);
            form3.setExceedMinutePrice(exceedMinutePrice);
            form3.setBaseReturnMileage(baseReturnMileage);
            form3.setExceedReturnPrice(exceedReturnPrice);
            form3.setChargeRuleId(chargeRuleId);

            ////调用订单子系统服务，调用成功后会返回orderId
            CommonResult commonResult3 = odrServiceApi.insertOrder(form3);
            String orderId = (String) commonResult3.get(CommonResult.RETURN_RESULT);

            result.put("orderId", orderId);
            result.put("count", list.size());

            /**
             * 发送通知给符合条件的司机抢单
             * */
            SendNewOrderMessageForm form5 = new SendNewOrderMessageForm();
            //对driverContent数组进行处理
            //list.size()就是司机的数量 创建一个司机容量的数组 数组多大就看有几个司机
            String[] driverContent = new String[list.size()];
            for (int i = 0; i < list.size(); i++) {
                HashMap map = list.get(i);
                String driverId = MapUtil.getStr(map, "driverId");
                String distance = MapUtil.getStr(map, "distance");
                //将距离保留一位小数 向上取整
                distance = new BigDecimal(distance).setScale(1, RoundingMode.CEILING).toString();
                driverContent[i] = driverId + "#" + distance;
            }
            form5.setDriversContent(driverContent);
            form5.setOrderId(Long.parseLong(orderId));
            //将订单公里数也取一位小数向上取整
            mileage = new BigDecimal(mileage).setScale(1, RoundingMode.CEILING).toString();
            form5.setMileage(mileage);
            form5.setExpectsFee(expectsFee);
            form5.setMinute(minute);
            form5.setFavourFee(favourFee);
            form5.setFrom(startPlace);
            form5.setTo(endPlace);

            snmServiceApi.sendNewOrderMessageAsync(form5);
        }
        return result;
    }

    @Override
    public Integer searchOrderStatus(SearchOrderStatusForm form) {
        CommonResult r = odrServiceApi.searchOrderStatus(form);
        Integer status = (Integer) r.get(CommonResult.RETURN_RESULT);
        return status;
    }

    @Override
    public String deleteUnAcceptOrder(DeleteUnAcceptOrderForm form) {
        CommonResult r = odrServiceApi.deleteUnAcceptOrder(form);
        String result = (String) r.get(CommonResult.RETURN_RESULT);
        return result;
    }

    @Override
    public HashMap hasCustomerCurrentOrder(HasCustomerCurrentOrderForm form) {
        CommonResult r = odrServiceApi.hasCustomerCurrentOrder(form);
        HashMap map = (HashMap) r.get(CommonResult.RETURN_RESULT);
        return map;
    }

    //查询订单信息用于司乘同显功能
    @Override
    public HashMap searchOrderForMoveById(SearchOrderForMoveByIdForm form) {
        CommonResult r = odrServiceApi.searchOrderForMoveById(form);
        HashMap hashMap = (HashMap) r.get(CommonResult.RETURN_RESULT);
        return hashMap;
    }

    @Override
    public Boolean confirmArriveStartPlace(ConfirmArriveStartPlaceForm form) {
        CommonResult r = odrServiceApi.confirmArriveStartPlace(form);
        Boolean result = MapUtil.getBool(r, CommonResult.RETURN_RESULT);
        return result;
    }

    @Override
    public HashMap searchOrderById(SearchOrderByIdForm form) {
        CommonResult r = odrServiceApi.searchOrderById(form);
        HashMap map = (HashMap) r.get(CommonResult.RETURN_RESULT);
        Long driverId = MapUtil.getLong(map, "driverId");
        if (driverId!=null) {
            //如果订单有司机就查询司机的信息
            SearchDriverBriefInfoForm infoForm = new SearchDriverBriefInfoForm();
            infoForm.setDriverId(driverId);
            r = drServiceApi.searchDriverBriefInfo(infoForm);
            HashMap temp = (HashMap) r.get(CommonResult.RETURN_RESULT);
            map.putAll(temp);
        }

        //补充代码
        //添加订单评价信息
        Integer status = MapUtil.getInt(map, "status");
        HashMap cmtMap = new HashMap();
        if (status>=7) {
            SearchCommentByOrderIdForm form_3 = new SearchCommentByOrderIdForm();
            form_3.setOrderId(form.getOrderId());
            form_3.setCustomerId(form.getCustomerId());
            r = odrServiceApi.searchCommentByOrderId(form_3);
            if (r.containsKey(CommonResult.RETURN_RESULT)) {
                //存在评价信息则取出
                cmtMap = (HashMap) r.get(CommonResult.RETURN_RESULT);
            }else{
                //不存在则默认为五星好评
                cmtMap.put("rate", "5");
            }
        }

        //把所有map信息都放在一个map中返回
        map.put("comment", cmtMap);

        return map;
    }


    //流程:核验订单是否为未支付->核验是否有可使用的优惠卷并且将订单与使用的优惠卷绑定->更新账单(扣除优惠卷费用的实付金额)->查询司机openId->查询客户openId->创建支付订单(
    //  1.构建发送请求参数 2.拿到返回参数 3.更新订单的prepay_id 4.构建小程序的加密后的支付署名 paySign 5.构建返回给小程序的参数)
    @Override
    @LcnTransaction
    @Transactional
    public HashMap createWxPayment(long orderId, long customerId, Long customerVoucherId, Long voucherId) {
        //1.校验该订单的状态是否为6(未支付),才可进行支付
        ValidCanPayOrderForm form_1 = new ValidCanPayOrderForm();
        form_1.setOrderId(orderId);
        form_1.setCustomerId(customerId);
        CommonResult r = odrServiceApi.validCanPayOrder(form_1);
        HashMap map = (HashMap) r.get(CommonResult.RETURN_RESULT);
        String amount = MapUtil.getStr(map, "realFee");
        String uuid = MapUtil.getStr(map, "uuid");
        Long driverId = MapUtil.getLong(map, "driverId");

        //2.校验优惠卷是否可用,若可用，则进行订单与优惠卷绑定
        String discount = "0.00";
        if (customerVoucherId != null && voucherId != null) {
            UseVoucherForm form_2 = new UseVoucherForm();
            form_2.setOrderId(orderId);
            form_2.setCustomerId(customerId);
            form_2.setVoucherId(voucherId);
            form_2.setId(customerVoucherId); //优惠卷ID
            form_2.setAmount(amount);
            r = vhrServiceApi.userVoucher(form_2);
            discount = (String) r.get(CommonResult.RETURN_RESULT);
        }
        //健壮性判断 在java中对浮点数不直接计算 因为浮点数计算会有误差 所以会借助BigDecimal类等
        if (new BigDecimal(discount).compareTo(new BigDecimal(amount)) == 1) {
            throw new GlobalException("总金额不能低于代金卷的金额");
        }
        //计算去掉代金卷后的金额
        amount = NumberUtil.sub(amount, discount).toString();

        //3.更新账单
        UpdateBillPaymentForm form_3 = new UpdateBillPaymentForm();
        form_3.setOrderId(orderId);
        form_3.setRealPay(amount);
        form_3.setVoucherFee(discount); //代金券面额
        r = odrServiceApi.updateBillPayment(form_3);
        int rows = (int) r.get("rows");
        if (rows != 1) {
            throw new GlobalException("更新账单失败");
        }

        //4.查询顾客openId
        SearchCustomerOpenIdForm form_4 = new SearchCustomerOpenIdForm();
        form_4.setCustomerId(customerId);
        r = cstServiceApi.searchCustomerOpenId(form_4);
        String customerOpenId = MapUtil.getStr(r, CommonResult.RETURN_RESULT);

        //5.查询司机openId
        SearchDriverOpenIdForm form_5 = new SearchDriverOpenIdForm();
        form_5.setDriverId(driverId);
        r = drServiceApi.searchDriverOpenId(form_5);
        String driverOpenId = MapUtil.getStr(r, CommonResult.RETURN_RESULT);

        //6.创建微信支付订单
        try {
            //创建微信支付对象
            WXPay wxPay = new WXPay(myWxPayConfig);
            //创建结果集(封装发送给微信平台的参数)
            HashMap<String, String> params = new HashMap<>();
            params.put("nonce_str", WXPayUtil.generateNonceStr());
            params.put("body", "代驾费");
            params.put("out_trade_no", uuid);
            params.put("attach", driverOpenId);
            params.put("openId", customerOpenId);
            //这里的总金额要求单位为分并为整数1元  =  100分
//            String totalAmount = NumberUtil.mul(amount,"100").setScale(0,RoundingMode.FLOOR).toString();
            params.put("total_fee", "4");
            params.put("spbill_create_ip","127.0.0.1");
            params.put("trade_type", "JSAPI");
            /*下面回调地址为微信支付成功后，微信会向该地址发送一个post请求 由于公网无法访问本机，所以这里利用内网穿透工具cpolar.top进行穿透 通过内网穿透工具将本机地址映射到公网
            * 当微信支付成功后，访问http://2756b4f5.r36.cpolar.top//fmdj/order/receiveMessage 实际请求的是http://127.0.0.1:8201/fmdj/order/receiveMessage
            * 走网关端口 再路由到对应的服务中
            * */
            params.put("notify_url", "http://2756b4f5.r36.cpolar.top//fmdj/order/receiveMessage");
            params.put("profit_sharing", "Y");
            Map result = wxPay.unifiedOrder(params);
            String prepayId = (String) result.get("prepay_id");

            if (prepayId!=null) {
                //当prepauId不为空时 更新到数据库
                UpdateOrderPrepayIdForm form_6 = new UpdateOrderPrepayIdForm();
                form_6.setOrderId(orderId);
                form_6.setPrepayId(prepayId);
                odrServiceApi.updateOrderPrepayId(form_6);

                //构建小程序的加密后的支付署名 paySign
                map.clear();
                map.put("appId", myWxPayConfig.getAppID());
                map.put("timeStamp", new Date().getTime() + " "); //时间戳 1970 年1月1日0时0分0秒 到现在的毫秒值
                map.put("nonceStr", WXPayUtil.generateNonceStr());
                map.put("package", "prepay_id=" + prepayId);
                map.put("signType", "MD5");
                String paySign = WXPayUtil.generateSignature(map, myWxPayConfig.getKey(), WXPayConstants.SignType.MD5);

                //构建返回给客户端(小程序)的结果集
                map.put("appId", myWxPayConfig.getAppID());
                map.put("timeStamp", new Date().getTime() + " ");
                map.put("nonceStr", WXPayUtil.generateNonceStr());
                map.put("paySign", paySign);
                //将来前端可以通过uuid 查询支付订单的状态
                map.put("uuid", uuid);

                return map;
            }else {
                log.error("创建支付订单失败");
                throw new GlobalException("创建支付订单失败");
            }
        } catch (Exception e) {
            log.error("创建支付订单失败");
            throw new GlobalException("创建支付订单失败");
        }

    }

    @Override
    public String updateOrderAboutPayment(UpdateOrderAboutPaymentForm form) {
        CommonResult r = odrServiceApi.updateOrderAboutPayment(form);
        String result = (String) r.get(CommonResult.RETURN_RESULT);
        return result;
    }

    @Override
    public PageUtils searchCustomerOrderByPage(SearchCustomerOrderByPageForm form) {
        CommonResult r = odrServiceApi.searchCustomerOrderByPage(form);
        HashMap map = (HashMap) r.get(CommonResult.RETURN_RESULT);
        PageUtils pageUtils = BeanUtil.toBean(map, PageUtils.class); /*将map中的键值复制到pageUtils中对应的属性中*/
        return pageUtils;
    }

}
